EDA: Caracterización y distribución de los datos#
Líbrerias y modulos necesarios#
import json
import warnings
import pandas as pd
import plotly.express as px
warnings.filterwarnings('ignore')
import plotly.graph_objects as go
from urllib.request import urlopen
from funciones import *
Conjunto de datos#
url = r"https://github.com/sePerezAlbor/Data/blob/main/data_to_eda.xlsx?raw=true"
data = pd.read_excel(url, na_values = [" "])
data.head()
| region_Def | Nombre_Departamento_Def | Nombre_Municipio_Def | Nombre_Departamento_Res | Nombre_Municipio_Res | sitio_def | año_def | mes_def | sexo | estado_civil | grupo_edad | nivel_edu | seg_social | asistencia_med | causa_basica | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | Orinoquía | META | VILLAVICENCIO | META | VILLAVICENCIO | Casa | 1985 | Enero | Femenino | Casado | 45-49 años | No especificado | Otro | NO | Parte no especificada |
| 1 | Andina | BOYACÁ | VENTAQUEMADA | BOYACÁ | VENTAQUEMADA | Casa | 1985 | Enero | Femenino | Soltero | 85+ años | No especificado | Otro | NO | Parte no especificada |
| 2 | Orinoquía | META | PUERTO LÓPEZ | META | PUERTO LÓPEZ | Casa | 1985 | Enero | Femenino | Casado | 50-54 años | No especificado | Otro | NO | Parte no especificada |
| 3 | Andina | HUILA | NEIVA | HUILA | NEIVA | Hospital o Clínica | 1985 | Enero | Femenino | Casado | 35-39 años | No especificado | Otro | NO | Parte no especificada |
| 4 | Andina | HUILA | NEIVA | HUILA | NEIVA | Casa | 1985 | Enero | Femenino | Casado | 75-79 años | No especificado | Otro | NO | Parte no especificada |
data.shape
(78479, 15)
Filtración conjunto de datos#
Antes de realizar el respectivo análisis descriptivo del conjunto de datos. Se filtrará este mismo solo para incluir mujeres mayores de 40 años.
data['grupo_edad'].value_counts()
grupo_edad
55-59 años 9373
60-64 años 9309
50-54 años 8708
65-69 años 8291
70-74 años 7473
45-49 años 6927
75-79 años 6151
80-84 años 4969
40-44 años 4880
85+ años 4554
Edad desconocida 3260
35-39 años 2777
30-34 años 1333
25-29 años 363
20-24 años 91
15-19 años 20
Name: count, dtype: int64
grupos_mayores_40 = [
'40-44 años', '45-49 años', '50-54 años', '55-59 años',
'60-64 años', '65-69 años', '70-74 años', '75-79 años',
'80-84 años', '85+ años'
]
data_mayores_40 = data[data['grupo_edad'].isin(grupos_mayores_40)]
data = data_mayores_40.copy()
# Diccionario de mapeo
grupo_mapeo = {
'40-44 años': '40-54 años',
'45-49 años': '40-54 años',
'50-54 años': '40-54 años',
'55-59 años': '55-64 años',
'60-64 años': '55-64 años',
'65-69 años': '65-74 años',
'70-74 años': '65-74 años',
'75-79 años': '75+ años',
'80-84 años': '75+ años',
'85+ años': '75+ años'
}
# Crear una nueva columna con los grupos
data['grupo_edad'] = data['grupo_edad'].map(grupo_mapeo)
data.shape
(70635, 15)
También se filtrará el conjunto de datos por los últimos tres quinquenios con los que se cuenta (2009 - 2023)
data_filtrada = data[(data['año_def']>= 2009) & (data['año_def']<= 2023)]
data_filtrada.shape
(41610, 15)
data = data_filtrada.copy()
Análisis general del conjunto de datos#
# Dividir en dos grupos (ajusta según necesidad)
categorical_columns = data.select_dtypes(include='object').columns
grupo1 = categorical_columns[:12] # Primeras 12 columnas
display(data[grupo1].describe())
| region_Def | Nombre_Departamento_Def | Nombre_Municipio_Def | Nombre_Departamento_Res | Nombre_Municipio_Res | sitio_def | mes_def | sexo | estado_civil | grupo_edad | nivel_edu | seg_social | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| count | 41610 | 41610 | 41610 | 41610 | 41610 | 41610 | 41610 | 41610 | 41610 | 41610 | 41610 | 41610 |
| unique | 5 | 33 | 841 | 33 | 944 | 3 | 12 | 1 | 4 | 4 | 6 | 5 |
| top | Andina | BOGOTA DC | BOGOTA DC | BOGOTA DC | BOGOTA DC | Hospital o Clínica | Diciembre | Femenino | Unión Libre, Divorciado/Otro | 55-64 años | Primaria | Contributivo |
| freq | 24900 | 8263 | 8263 | 6954 | 7437 | 28549 | 3692 | 41610 | 11647 | 11157 | 15416 | 21075 |
Veamos la cantidad de datos faltantes en general.
grafico_datos_faltantes(data)
Análisis Univariado#
Variable: Región de defunción#
grafico_circular_categorico(data, 'region_Def', 'Distribución de Defunciones por Región')
grafico_barras_categoricas(data, 'region_Def', 'Distribución de Defunciones por Región', 'Defunciones', 'Número de Defunciones')
Variable: Departamento de defunción#
top_10_departamentos = data['Nombre_Departamento_Def'].value_counts().head(10).index
# Filtrar el DataFrame original para que solo contenga esos departamentos
data_top10 = data[data['Nombre_Departamento_Def'].isin(top_10_departamentos)]
# Llamar la función original con el nombre de la columna
grafico_barras_categoricas(data_top10, 'Nombre_Departamento_Def', 'Departamento', 'Cantidad de defunciones', 'Defunciones por departamento (Top 10)')
bottom_10_departamentos = data['Nombre_Departamento_Def'].value_counts().tail(10).index
data_bottom10 = data[data['Nombre_Departamento_Def'].isin(bottom_10_departamentos)]
# Reemplazar el nombre largo por uno más corto en una copia del DataFrame
data_bottom10['Nombre_Departamento_Def'] = data_bottom10['Nombre_Departamento_Def'].replace(
'ARCHIPIÉLAGO DE SAN ANDRÉS Y PROVIDENCIA Y SANTA CATALINA',
'SAN ANDRÉS'
)
grafico_barras_categoricas(data_bottom10, 'Nombre_Departamento_Def', 'Departamento', 'Cantidad de defunciones', 'Defunciones por departamento (Bottom 10)')
Variable: Municipio#
top_10_municipios = data['Nombre_Municipio_Def'].value_counts().head(10).index
data_top10_mun = data[data['Nombre_Municipio_Def'].isin(top_10_municipios)]
grafico_barras_categoricas(data_top10_mun, 'Nombre_Municipio_Def', 'Municipio', 'Cantidad de defunciones', 'Defunciones por municipio (Top 10)')
Variable: Sitio de defunción#
grafico_barras_categoricas(data, 'sitio_def', 'Sitio de defunción', 'Cantidad de registros', 'Distribución sitio de defunción')
grafico_circular_categorico(data, 'sitio_def', 'Distribución de Defunciones por Sitio de Defunción')
Variable: Estado civil#
grafico_barras_categoricas(data, 'estado_civil', 'Estado civil', 'Cantidad de registros', 'Distribución estado civil')
grafico_circular_categorico(data, 'estado_civil', 'Distribución de Defunciones por Estado Civil')
Variable: Grupo de edad#
grafico_edad(data, 'Grupo de edad', 'Cantidad de registros', 'Distribución de Defunciones por Edad')
grafico_barras_categoricas(data, 'grupo_edad', 'Grupo de edad', 'Cantidad de registros', 'Distribución por grupo de edad')
Variable: Nivel educativo#
grafico_barras_categoricas(data, 'nivel_edu', 'Nivel educativo', 'Cantidad de registros', 'Distribución nivel educativo')
grafico_circular_categorico(data, 'nivel_edu', 'Distribución de Defunciones por Nivel Educativo')
Variable: Asistencia médica#
grafico_barras_categoricas(data, 'asistencia_med', 'Asistencia médica', 'Cantidad de registros', 'Distribución asistencia médica')
grafico_circular_categorico(data, 'asistencia_med', 'Distribución de Defunciones por Asistencia Médica')
Variable: Causa básica#
grafico_barras_categoricas(data, 'causa_basica', 'Causa básica', 'Cantidad de registros', 'Distribución causa básica')
Variable: Mes de defunción#
grafico_mes_def(data, 'Mes de defunción', 'Cantidad de registros', 'Distribución de Defunciones por Mes')
grafico_barras_categoricas(data, 'mes_def', 'Mes de defunción', 'Cantidad de registros', 'Distribución de Defunciones por Mes de mayor a menor')
Análisis Bivariado#
Tendencia de defunciones por año y región#
data_grouped = data.groupby(['año_def', 'region_Def']).size().reset_index(name='Defunciones')
color_palette = ["#ffb6c1", "#ff69b4", "#db7093", "#c71585",
"#ff1493", "#e60073", "#cc0033", "#b20000"]
fig6 = px.line(data_grouped,
x='año_def',
y='Defunciones',
color='region_Def',
title='Tendencia de Defunciones por Año y Región',
markers=True, # Agregar marcadores
color_discrete_sequence=color_palette) # Aplicar paleta personalizada
fig6.update_layout(
font=dict(family="Bahnschrift", color="black"), # Fuente Bahnschrift en negro
xaxis_title="Año de Defunción",
yaxis_title="Número de Defunciones",
legend_title="Región", # Título de la leyenda
template="plotly_white" # Fondo blanco para mayor claridad
)
fig6.show()
Evolución de las Defunciones según el Lugar de Muerte#
# Agrupar datos por año de defunción y sitio de defunción
data_grouped = data.groupby(["año_def", "sitio_def"]).size().reset_index(name="count")
# Gráfico de líneas con tonalidades rosadas
fig = px.line(data_grouped,
x="año_def",
y="count",
color="sitio_def",
markers=True, # Agregar puntos en la línea
title="Evolución de las Defunciones según el Lugar de Muerte",
color_discrete_sequence=["#ffb6c1", "#ff69b4", "#db7093", "#c71585"]) # Tonos rosados
fig.update_layout(
font=dict(family="Bahnschrift", color="black"),
xaxis_title="Año de Defunción",
yaxis_title="Número de Defunciones",
legend_title="Lugar de Defunción",
template="plotly_white"
)
fig.show()
Evolución de Defunciones por Grupo de Edad#
data_grouped = data.groupby(["año_def", "grupo_edad"]).size().reset_index(name="count")
color_palette = ["#ffb6c1", "#ff69b4", "#db7093", "#c71585",
"#ff1493", "#e60073", "#cc0033", "#b20000",
"#990000", "#800000", "#ff3366", "#ff0033",
"#d40000", "#a10000"]
fig = px.line(data_grouped,
x="año_def",
y="count",
color="grupo_edad",
title="Evolución de Defunciones por Grupo de Edad",
markers=True, # Agregar puntos en la línea
color_discrete_sequence=color_palette, # Aplicar paleta de colores
labels={"grupo_edad": "Grupo de Edad", "año_def": "Año", "count": "Número de Defunciones"})
fig.update_layout(
font=dict(family="Bahnschrift", color="black"), # Fuente en negro
xaxis_title="Año de Defunción",
yaxis_title="Número de Defunciones",
legend_title="Grupo de Edad",
width=800,
height=600,
template="plotly_white"
)
fig.show()
Análisis de los casos a lo largo del tiempo#
meses_map = {
"Enero": "01", "Febrero": "02", "Marzo": "03", "Abril": "04", "Mayo": "05", "Junio": "06",
"Julio": "07", "Agosto": "08", "Septiembre": "09", "Octubre": "10", "Noviembre": "11", "Diciembre": "12"
}
data['mes_def'] = data['mes_def'].map(meses_map)
data['Fecha'] = data['año_def'].astype(str) + '-' + data['mes_def']
conteo_fechas = data['Fecha'].value_counts().reset_index()
conteo_fechas.columns = ['Fecha', 'Cantidad']
conteo_fechas = conteo_fechas.sort_values('Fecha')
conteo_fechas['Fecha'] = pd.to_datetime(conteo_fechas['Fecha'], format='%Y-%m')
fig = px.line(conteo_fechas,
x='Fecha',
y='Cantidad',
title="Casos de Defunción a lo Largo del Tiempo",
labels={'Cantidad': 'Número de Defunciones', 'Fecha': 'Fecha'},
markers=True)
fig.update_traces(line=dict(color="#C2185B"),
marker=dict(color="#F06292", size=8))
fig.update_layout(
template="plotly_white",
xaxis_title="Fecha",
yaxis_title="Número de Defunciones",
font=dict(family="Bahnschrift", size=14, color="black"),
title_font=dict(family="Bahnschrift", size=22, color="black"),
plot_bgcolor="white",
paper_bgcolor="white"
)
fig.show()
Mapa de casos por departamento#
with urlopen('https://raw.githubusercontent.com/lihkir/Uninorte/main/AppliedStatisticMS/DataVisualizationRPython/Lectures/Python/PythonDataSets/Colombia.geo.json') as response:
counties = json.load(response)
locs=[]; z_id=[];
for loc in counties['features']:
loc['id'] = loc['properties']['NOMBRE_DPT']
locs.append(loc['properties']['NOMBRE_DPT'])
z_id.append(loc['properties']['HECTARES'])
colorscale = [
[0, "#fde0dc"], # Rosa claro
[0.2, "#f9bdbb"],
[0.4, "#f69988"],
[0.6, "#f36c60"],
[0.8, "#e84e40"],
[1, "#d50000"] # Rojo intenso
]
# Contar la cantidad de casos por departamento
casos_por_departamento = data['Nombre_Departamento_Def'].value_counts().reset_index()
casos_por_departamento.columns = ['Nombre_Departamento_Def', 'Casos']
# Reemplazar nombres para que coincidan con el GeoJSON
correccion_nombres = {
'ATLÁNTICO': 'ATLANTICO',
'BOLÍVAR': 'BOLIVAR',
'BOGOTA DC': 'SANTAFE DE BOGOTA D.C',
'BOYACÁ': 'BOYACA',
'CÓRDOBA': 'CORDOBA',
'CAQUETÁ': 'CAQUETA',
'CHOCÓ': 'CHOCO',
'LA GUAJIRA': 'LA GUAJIRA',
'ARCHIPIÉLAGO DE SAN ANDRÉS Y PROVIDENCIA Y SANTA CATALINA': 'ARCHIPIELAGO DE SAN ANDRES PROVIDENCIA Y SANTA CATALINA',
'GUAINÍA': 'GUAINIA',
'GUAVIARE': 'GUAVIARE',
'VAUPÉS': 'VAUPES',
'VICHADA': 'VICHADA'
}
casos_por_departamento['Nombre_Departamento_Def'] = casos_por_departamento['Nombre_Departamento_Def'].replace(correccion_nombres)
locs = casos_por_departamento['Nombre_Departamento_Def'].tolist()
z_id = casos_por_departamento['Casos'].tolist()
fig = go.Figure(go.Choroplethmapbox(
geojson=counties,
locations=locs,
z=z_id,
colorscale= colorscale,
colorbar_title="Casos de Defunción"))
fig.update_layout(mapbox_style="open-street-map",
mapbox_zoom=4,
mapbox_center={"lat": 4.570868, "lon": -74.2973328} ,width=800,
height=600 )
fig.show()
data.to_csv('../data_to_models.csv')